#include "interface_spiflash.h"
#include "gd32f4xx.h"


#define FLASH_OK 0

/**********************************************************
 * �� �� �� �ƣ�w25q64_init_config
 * �� �� �� �ܣ�w25q64��ʼ��
 * �� �� �� ������
 * �� �� �� �أ���
 * ��       �ߣ�LCKFB
 * ��       ע����
**********************************************************/
int w25q64_init_config(void)
{	
	//SPI��������ṹ��
	spi_parameter_struct spi_init_struct;
	
	rcu_periph_clock_enable(RCU_GPIOG);  // ʹ��G�˿�
	rcu_periph_clock_enable(RCU_SPI5);     // ʹ��SPI5
	//���Ÿ���
	gpio_af_set(GPIOG, GPIO_AF_5, GPIO_PIN_12);
	gpio_af_set(GPIOG, GPIO_AF_5, GPIO_PIN_13);
	gpio_af_set(GPIOG, GPIO_AF_5, GPIO_PIN_14);
	//����ģʽ
	gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_12);
	gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_13);
	gpio_mode_set(GPIOG, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_14);
	//���ģʽ
	gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_12);
	gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
	gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_14);
    
	// /* ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬
	//����CS����ģʽ
	gpio_mode_set(GPIOG, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_11);
	//����CS���ģʽ
	gpio_output_options_set(GPIOG, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
	//W25Q64��ѡ��
	gpio_bit_write(GPIOG, GPIO_PIN_11, SET);
	// */

	spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;  	// ����ģʽȫ˫��
	spi_init_struct.device_mode          = SPI_MASTER;                	// ����Ϊ����
	spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;        	// 8λ����
	spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE;		//������λ  
	spi_init_struct.nss                  = SPI_NSS_SOFT;              	//����cs
	spi_init_struct.prescale             = SPI_PSC_2;                 	//SPIʱ��Ԥ��ƵΪ2
	spi_init_struct.endian               = SPI_ENDIAN_MSB;            	//��λ��ǰ
	//����������SPI5
	spi_init(SPI5, &spi_init_struct);

	//ʹ��SPI
	spi_enable(SPI5);

	return FLASH_OK;		    	      

}
/******************************************************************
 * �� �� �� �ƣ�spi_read_write_byte
 * �� �� ˵ ����Ӳ��SPI�Ķ�д
 * �� �� �� �Σ�dat=���͵�����
 * �� �� �� �أ���ȡ��������
 * ��       �ߣ�LCKFB
 * ��       ע����
******************************************************************/
uint8_t spi_read_write_byte(uint8_t dat)
{
	//�ȴ����ͻ�����Ϊ��
	while(RESET == spi_i2s_flag_get(SPI5,  SPI_FLAG_TBE) );
         spi_i2s_data_transmit(SPI5, dat);
	//�ȴ����ջ�����Ϊ��
	while(RESET == spi_i2s_flag_get(SPI5,  SPI_FLAG_RBNE) );
         return spi_i2s_data_receive(SPI5);
}

/******************************************************************
 * �� �� �� �ƣ�W25Q64_readID
 * �� �� ˵ ������ȡW25Q64�ĳ���ID���豸ID
 * �� �� �� �Σ���
 * �� �� �� �أ��豸��������EF16
 * ��       �ߣ�LCKFB
 * ��       ע����
******************************************************************/
uint16_t W25Q64_readID(void)
{
	uint16_t  temp = 0;	  
	
	gpio_bit_write(GPIOG, GPIO_PIN_11, RESET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬
		
	spi_read_write_byte(0x90);//���Ͷ�ȡID����	    
	spi_read_write_byte(0x00); 	    
	spi_read_write_byte(0x00); 	    
	spi_read_write_byte(0x00); 		
	//��������
	temp |= spi_read_write_byte(0xFF)<<8;  
	temp |= spi_read_write_byte(0xFF);	
		 
	gpio_bit_write(GPIOG, GPIO_PIN_11, SET);	//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬
	return temp;
}



/**********************************************************
 * �� �� �� �ƣ�W25Q64_wait_busy
 * �� �� �� �ܣ��ж�W25Q64�Ƿ�æ
 * �� �� �� ������
 * �� �� �� �أ���
 * ��       �ߣ�LCKFB
 * ��       ע����
**********************************************************/
void W25Q64_wait_busy(void)   
{   
    unsigned char byte = 0;
    do
     { 
       gpio_bit_write(GPIOG, GPIO_PIN_11, RESET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬                              
        spi_read_write_byte(0x05);                 
        byte = spi_read_write_byte(0Xff);       
       gpio_bit_write(GPIOG, GPIO_PIN_11, SET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬         
     }while( ( byte & 0x01 ) == 1 );  
}  

/**********************************************************
 * �� �� �� �ƣ�W25Q64_write_enable
 * �� �� �� �ܣ�����дʹ��
 * �� �� �� ������
 * �� �� �� �أ���
 * ��       �ߣ�LCKFB
 * ��       ע����
**********************************************************/
void W25Q64_write_enable(void)   
{
   gpio_bit_write(GPIOG, GPIO_PIN_11, RESET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬                           
    spi_read_write_byte(0x06);                  
   gpio_bit_write(GPIOG, GPIO_PIN_11, SET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬ 
}                            	      

/**********************************************************
 * �� �� �� �ƣ�W25Q64_erase_sector
 * �� �� �� �ܣ�����һ������
 * �� �� �� ����addr=������������
 * �� �� �� �أ���
 * ��       �ߣ�LCKFB
 * ��       ע��addr=�����������ţ���Χ=0~15
**********************************************************/
int W25Q64_erase_sector(uint32_t addr)   
{
	// addr *= 4096;
	// printf("erase_sector addr:%x\n", addr);
	// printf("erase_sector addr:%x %x %x\n", addr>>16,addr>>8, addr );
	W25Q64_write_enable();  //дʹ��   
	W25Q64_wait_busy();     //�ж�æ 
	gpio_bit_write(GPIOG, GPIO_PIN_11, RESET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬                                        
	spi_read_write_byte(0x20);        	
	spi_read_write_byte((uint8_t)((addr)>>16));      
	spi_read_write_byte((uint8_t)((addr)>>8));   
	spi_read_write_byte((uint8_t)addr);  
	gpio_bit_write(GPIOG, GPIO_PIN_11, SET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬                  
	//�ȴ��������                           	      	 
	W25Q64_wait_busy();   
	return FLASH_OK;		    	      
}         

int W25x_SectorErase(uint32_t SectorAddr, uint32_t size)
{
    // if (spiHandle == NULL) {
    //     HDF_LOGE("SPI flash hasn't been initialized\n");
    //     return;
    // }
	// printf("SectorErase addr:%x %d\n", SectorAddr,  size);

    // 将擦除操作分割为多个扇区操作
    uint32_t endAddr = SectorAddr + size;
    uint32_t sectorAddr = SectorAddr;

    // 确保擦除操作是按扇区大小对齐的
    // 假设每个扇区是 4KB
    uint32_t sectorSize = 4096;  // 一般来说，每个扇区的大小为4KB
    if (sectorAddr % sectorSize != 0) {
        printf("Start address is not aligned to sector size\n");
        return;
    }
    if (size % sectorSize != 0) {
        printf("Erase size is not aligned to sector size\n");
        return;
    }

    // 擦除每个扇区，直到达到所需的结束地址
    while (sectorAddr < endAddr) {

        // printf("W25x_SectorErase addr:%x  size:%x\n", sectorAddr, size);
		W25Q64_erase_sector(sectorAddr);
        // 移动到下一个扇区
        sectorAddr += sectorSize;
    }
	return FLASH_OK;		    	      
}				                      	      


/**********************************************************
 * �� �� �� �ƣ�W25Q64_write
 * �� �� �� �ܣ�д���ݵ�W25Q64���б���
 * �� �� �� ����buffer=д�����������	addr=д���ַ	numbyte=д�����ݵĳ���
 * �� �� �� �أ���
 * ��       �ߣ�LCKFB
 * ��       ע����
**********************************************************/
int W25Q64_write(uint8_t* buffer, uint32_t addr, uint16_t numbyte)
{    //0x02e21
    // printf("addr:%x size:%d %d %s %s\n",addr,numbyte,__LINE__,__FILE__, buffer);
    unsigned int i = 0;
    W25Q64_erase_sector(addr/4096);//������������
    W25Q64_write_enable();//дʹ��    
    W25Q64_wait_busy(); //æ���    
    //д������
   gpio_bit_write(GPIOG, GPIO_PIN_11, RESET); //ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬                                       
    spi_read_write_byte(0x02);                    
    spi_read_write_byte((uint8_t)((addr)>>16));     
    spi_read_write_byte((uint8_t)((addr)>>8));   
    spi_read_write_byte((uint8_t)addr);   
    for(i=0;i<numbyte;i++)
    {
        spi_read_write_byte(buffer[i]);  
    }
   gpio_bit_write(GPIOG, GPIO_PIN_11, SET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬
    W25Q64_wait_busy(); //æ���      
	return FLASH_OK;		    	      
}

/**********************************************************
 * �� �� �� �ƣ�W25Q64_read
 * �� �� �� �ܣ���ȡW25Q64������
 * �� �� �� ����buffer=�������ݵı����ַ  read_addr=��ȡ��ַ		read_length=��ȥ����
 * �� �� �� �أ���
 * ��       �ߣ�LCKFB
 * ��       ע����
**********************************************************/
int W25Q64_read(uint8_t* buffer,uint32_t read_addr,uint16_t read_length)   
{ 
	uint16_t i;   		
	gpio_bit_write(GPIOG, GPIO_PIN_11, RESET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬            
	spi_read_write_byte(0x03);                           
	spi_read_write_byte((uint8_t)((read_addr)>>16));           
	spi_read_write_byte((uint8_t)((read_addr)>>8));   
	spi_read_write_byte((uint8_t)read_addr);   
	for(i=0;i<read_length;i++)
	{ 
		buffer[i]= spi_read_write_byte(0XFF);  
	}
	gpio_bit_write(GPIOG, GPIO_PIN_11, SET);//ʵ�ʵ�·��δ����CS�������ţ�һֱ��������ѡ��״̬  
	return FLASH_OK;		    	      
} 

int testspi(void)
{
	uint8_t buff[10];
		//��ȡ0��ַ��5���ֽ����ݵ�buff
	W25Q64_read(buff, 0, 5);
	printf("testspi1:%s\n",buff);
	
	//��0��ַд��5���ֽڳ��ȵ����� ABCD
	W25Q64_write("ABCD", 0, 5);
	
	//��ȡ0��ַ��5���ֽ����ݵ�buff
	W25Q64_read(buff, 0, 5);
	printf("testspi2:%s\n",buff);
	return FLASH_OK;		    	      
}

